#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "memory_dump.h"
#include "test_for_pointer.h"
#include "test_for_sizeof.h"
#include "test_for_const.h"
#include "test_for_singly_linked_list.h"
#include "test_for_hash.h"
#include "test_for_circular_linked_list.h"
#include "test_for_twosum.h"

typedef union
{
    uint16_t output_data;
    struct
    {
        uint16_t bit1:1;
        uint16_t bit2:1;
        uint16_t resv:13;
        uint16_t bit16:1;
    }bits;
    uint8_t data_temp[2];
}Chip_CAT;

struct dsb
{
    uint32_t bit1:1;
    uint32_t bit2:2;
    uint32_t resv:9;
    uint32_t bit4:2;
    uint32_t bit16:7;
};

typedef union
{
    uint16_t value;
    struct
    {
        uint16_t low_bit0_CHRG_INHIBIT     : 1;
        uint16_t low_bit1_EN_IDPM          : 1;
        uint16_t low_bit2_EN_LDO           : 1;
        uint16_t low_bit3_IBAT_GAIN        : 1;
        uint16_t low_bit4_IADPT_GAIN       : 1;
        uint16_t low_bit5_EN_LEARN         : 1;
        uint16_t low_bit6_bit7_reserved    : 2;
        uint16_t hig_bit0_reserved         : 1;
        uint16_t hig_bit1_PWM_FREQ         : 1;
        uint16_t hig_bit2_EN_OOA           : 1;
        uint16_t hig_bit3_OTG_ON_CHRGOK    : 1;
        uint16_t hig_bit4_IDPM_AUTO_DISABLE: 1;
        uint16_t hig_bit5_bit6_WDTMR_ADJ   : 2;
        uint16_t hig_bit7_EN_LWPWR         : 1;
    }bits;
}reg0x00_01_config_t;

Chip_CAT CAT95551;

struct dsb bb1;

uint32_t mine = 0x12345678; //此变量用于验证存储大小端
reg0x00_01_config_t reg_0x00_01 = {.value = 0xE20E};

char* my_strcat(char* dst, const char* src);
void* mymemcpy(void* dst, void* src, int len);
char* mystrcpy(char* dst, const char* src);
char* mystrncpy(char* dst, const char* src, size_t n);
void bubbleSort(uint32_t arr[], size_t n);
void print_prime(unsigned int prime);
int* twoSum(int* nums, int numsSize, int target, int* returnSize);
int removeDuplicates(int* nums, int numsSize);
void kkk(uint16_t current);
int twoSum_x[] = {2,7,11,15};
int nums_ret[2] = {0};

int numsx[] = {1,1,2};
// int numsx[] = {0,0,1,1,1,2,2,3,3,4};
int ret_k = 0;

#include <stdio.h>
#include <stdint.h>

#pragma pack(push)
#pragma pack(4)

struct aaa
{
	uint8_t u8Data1;
	uint16_t u16Data2;
	uint8_t u8Array[2];
}wow;

struct aaa x2;
	
union
{
	struct aaa x1;
	uint8_t u8Array1[5];
	uint16_t u16Data3;
}dataSize;

#pragma pack(pop)

/// @brief 
/// @param argc 
/// @param argv 
/// @return 
int main(int argc, char* argv[])
{
    char str1[20] = "";
    char str2[20] = "world hello chenji";

    char destination[10] = "123";
    char source[10] = "456";
    char* ttt = "";

    char str3[] = "you are abc";
    char str4[] = "ccc\n";

    char str5[20] = "you you check now!";
    char str6[20] = "ok\n";

    uint32_t bubble_arr[] = {1,5,2,0,30,7,10};

    CAT95551.bits.bit1 = 1;
    CAT95551.bits.bit2 = 1;
    CAT95551.bits.bit16 = 1;
    bb1.bit1 = 0b1;
    bb1.bit2 = 0b10;
    bb1.resv = 0b100100100;
    bb1.bit4 = 0b10;
    bb1.bit16 = 0b1001001; //编译器会尽可能的合并位到基本类型中，如果不能够直接合并的，会按照尽量少次数存取的思路来存储。举例见-C语言位域（位段）的定义整理（童光强）
    
    memory_dump(&bb1, 4, &bb1,&bb1);
    //强转地址为uint32_t，打印短地址（忽略警告），和memory_dump打印的内容做一个印证
    printf("addr0:0x%04X:%02X\n",(uint32_t)((char*)(&bb1)),*((char*)(&bb1)));
    printf("addr1:0x%04X:%02X\n",(uint32_t)((char*)(&bb1)+1),*((char*)(&bb1)+1));
    printf("addr2:0x%04X:%02X\n",(uint32_t)((char*)(&bb1)+2),*((char*)(&bb1)+2));
    printf("addr3:0x%04X:%02X\n",(uint32_t)((char*)(&bb1)+3),*((char*)(&bb1)+3));

    if((*(char* )&mine) == 0x78) //大小端判断
    {
        memory_dump(&mine, 4, &mine,&mine);
        printf(LIGHT_CYAN "addr = 0x%04X,little endian\n" NONE,(uint32_t)&mine);
    }
    else
    {
        printf("big endian\n");
    }

    //打印位域中的成员的值
    printf("bit1:%d\n",CAT95551.bits.bit1);
    printf("bit2:%d\n",CAT95551.bits.bit2);
    printf("bit16:%d\n",CAT95551.bits.bit16);

    ttt = my_strcat(destination,source);

    printf("%s\n",ttt);

    mymemcpy(str1,str2,strlen(str2));
    printf(YELLOW "%s\n" NONE,str1);

    printf(LIGHT_RED "test for pointer\n" NONE);
    test_for_pointer();

    printf(LIGHT_RED "test for mystrcpy\n" NONE);
    mystrcpy(str3+4,str4);
    printf(str3);

    printf(LIGHT_RED "test for mystrncpy\n" NONE);
    mystrncpy(str5+4, str6, strlen(str6) + 1); //注意：strlen()函数计算字符串长度不包含结束符 '\0'
    printf(str5);

    bubbleSort(bubble_arr, 7);

    test_for_sizeof();
    test_for_hash();
    test_for_const();
    test_for_singly_linked_list();
    test_for_circular_linked_list();
    // print_prime(10000);
    // twoSum(twoSum_x, 4, 9, NULL);
    test_for_twosum();
    ret_k = removeDuplicates(numsx, sizeof(numsx) / sizeof(int));
    printf("ret_k:%d\r\n", ret_k);
    for(int i = 0; i < sizeof(numsx) / sizeof(int); i++)
    {
        printf("%d,", numsx[i]);
    }

    printf("\n:%d\n",sizeof(x2));
	printf("\n:%d\n",sizeof(dataSize));
    kkk(4000);

    reg_0x00_01.bits.low_bit2_EN_LDO = 0;
    printf("reg0x00_01:%04X\r\n", reg_0x00_01.value);

    return 0;
}

char* my_strcat(char* dst, const char* src)
{
    char* temp = dst;
    if(dst == NULL || src == NULL)
    {
        return NULL;
    }
    while(*dst != '\0')
    {
        dst++;
    }

    while(*src != '\0')
    {
        *(dst++) = *(src++);
    }

    return temp;
}

/**
 * @brief 将其中的源地址和目的地址得操作使用隐式类型转换
 * -->static_cast <type> () 注意：这个用于C++
 * @param dst 
 * @param src 
 * @param len 
 * @return void* 
 */
void* mymemcpy(void* dst, void* src, int len)
{
    void* temp = dst;
    char* pDst =  (char* )(dst);
    char* pSrc =  (char* )(src);

    if(dst == NULL || src == NULL)
    {
        return NULL;
    }

    while(len--)
    {
        *pDst++ = *pSrc++;
    }

    return temp;
}

/**
 * @brief 用mymemmove()比mymemcpy更安全，可以解决内存重叠问题
 * 
 * @param dst 
 * @param src 
 * @param n 
 * @return void* 
 */
void* mymemmove(void* dst, void* src, size_t n)
{
	void* temp = dst;
	char* pDst =  (char* )(dst);
	char* pSrc =  (char* )(src);
	
	if(dst == NULL || src == NULL)
	{
		return NULL;
	}
	if(pSrc >= pDst)
	{
		while(n--)
		{
			*pDst++ = *pSrc++;
		}
	}
	else
	{
		pDst = pDst + (n - 1);
		pSrc = pSrc + (n - 1);
		while(n--)
		{
			*pDst-- = *pSrc--;
		}
	}
	return temp;	
}

/**
 * @brief mystrcpy() 字符串拷贝函数；源指针的结束符 拷贝到 目标指针 即终止
 * 
 */
char* mystrcpy(char* dst, const char* src)
{
    char* temp = dst;
    if(dst == NULL || src == NULL)
    {
        return NULL;
    }

    /*此段代码解读，参考链接： https://blog.csdn.net/qiqisunshine/article/details/77185019 */
    // while((*dst++ = *src++) != '\0');
    
    /*上面这句话，语句简洁不易读，可以等价修改为以下代码段：*/
    while(*dst != '\0')
    {
        *dst++ = *src++;
    }

    return temp;
}

/**
 * @brief mystrncpy() 字符串指定长度拷贝函数；源指针的结束符 拷贝到 目标指针 即终止
 * 
 */
char* mystrncpy(char* dst, const char* src, size_t n)
{
    char* temp = dst;
    if(dst == NULL || src == NULL)
    {
        return NULL;
    }

    while(n--)
    {
        if(*dst != '\0')
        {
            *dst++ = *src++;
        }
    }
    return temp;
}

/**
 * @brief 冒泡排序实现
 * @param arr[] 要排序的数组
 * @param n 要排序的数据项数
 * @return void
 */
void bubbleSort(uint32_t arr[], size_t n)
{
    uint32_t temp = 0;
    uint16_t i = 0,j = 0;
    for(i = 0; i < n - 1; i++)
    {
        for(j = i + 1; j < n; j++)
        {
            if(arr[i] <= arr[j]) /* <= 升序排序    >= 降序排序 */
            {
                continue;
            }
            else //交换
            {
                temp = arr[j];
                arr[j] = arr[i];
                arr[i] = temp;
            }
        }
    }
}

/**
 * @brief 传入一个正整数，打印范围内的所有质数（只能被 1 和自身整除的数）
 */
void print_prime(unsigned int prime)
{
    uint32_t max_prime = 0;
    printf(GREEN "test for prime!\n");
    printf("1, ");
    for(uint32_t i = 1; i < prime; i++)
    {
        for(uint32_t j = 2; j <= i; j++)
        {
            if((i % j == 0) && (i != j))
            {
                break;
            }
            else if((i % j == 0) && (i == j))
            {
                printf("%d, ", i);
                if(i > max_prime)
                {
                    max_prime = i;
                }
            }
        }
        if(i % 30 == 0)
        {
            printf("\n");
        }
    }
    printf(LIGHT_RED "\nmax prime:%d\n" NONE, max_prime);
}

// int* twoSum(int* nums, int numsSize, int target, int* returnSize)
// {
//     int* nums_ret = (int* )malloc(sizeof(int) * 2);
//     int i = 0, j = 0;
//     int flag = 0;
//     for(i = 0; i < numsSize; i++)
//     {
//         nums_ret[0] = i;
//         for(j = i + 1; j < numsSize; j++)
//         {
//             if(nums[i] == target - nums[j])
//             {
//                 nums_ret[1] = j;
//                 return nums_ret;
//             }
//         }
//     }
//     return NULL;
// }

int removeDuplicates(int* nums, int numsSize)
{
    int i = 1, j = 2;
    while(j < numsSize)
    {
        if(nums[i] != nums[j])
        {
            nums[i] = nums[j];
        }

        while(nums[i] == nums[j])
        {
            j++;
        }
        i++;
    }
    return i;
}

void kkk(uint16_t current)
{
    uint8_t id_temp[2] = {0};
    if(current > 8128 || current < 64) // 数据超出范围
    {
        return;
    }
    // 根据手册对寄存器的描述，处理数据
    current &= 0x1FC0;
    *(uint16_t* )&id_temp[0] = current; //符合小端序，直接强制转换
    printf("cur:%04X\r\n"
           "id_tmp[0]:%02X\r\n"
           "id_tmp[1]:%02X\r\n", current, id_temp[0], id_temp[1]);
}